// TODO: Need to implement representations that are completely abstract, so that could be a mix of double, int, etc.
//
// TODO: Many of the subroutines need to stop taking return arguments to modify in place.
//
// TODO: NOTE: Why are there no operations that introduce entirely new individuals to the population each generation?
//
// TODO: NOTE: new_individual() could rely on new_gene() (internally here in EA) as a default. This would simplify things (for default).
//
// TODO: NOTE: Could mutate_gene() be moved internally to EA (also just by a default), with bounds and PBC?. This (again) would simplify things (for default).
// TODO: NOTE: ... I suppose that one concern though is that there may not be a "one-size fits all" for mutate_gene() --- e.g., a normally distributed random number, same for each gene, etc.

// TODO: NOTE: Should implement some default wrappers [e.g., for new_individual(), which would just wrap to new_gene()].
//
// TODO: NOTE: ... This is currently left as input, so that "seeding" may occur.

// TODO: NOTE: IF new_gene() is (completely) randomly selecting from some pool, then could simplify this subroutine by not needing to pass this subroutine (but pass pool information instead).

// TODO: NOTE: Perhaps should change EAParam variable frac_elite to nelite, since we are often interested in specifying the number of elite individuals (not a fraction).

#ifndef STATSxx_OPTIMIZATION_EA_HPP
#define STATSxx_OPTIMIZATION_EA_HPP


// STL
#include <functional>                          // std::function<>
#include <vector>                              // std::vector<>

// this
#include "statsxx/optimization/EA/EAParam.hpp" // EAParam


//
// TODO: NOTE: Maybe the new_individual() is to return a new Individual?
//
std::vector<double> EA(
                       const std::function<std::vector<double>()>                            &new_individual,
                       // -----
                       const std::function<double(const int, const std::vector<double> &)>   &new_gene,
                       // =====
                       const std::function<double(const int, const std::vector<double> &)>   &mutate_gene,
                       // =====
                       const std::function<double(const std::vector<double> &)>              &fitness,
                       // -----
                       const std::vector<std::function<double(const std::vector<double> &)>> &inequality_constraints,
                       const std::vector<std::function<double(const std::vector<double> &)>> &equality_constraints,
                       // =====
                       const std::function<bool(const std::vector<double> &)>                &convergence_function,
                       // *****
                       const EAParam                                                         &param
                       );
#include "statsxx/optimization/EA/EA/EA.cpp"


#endif
